package com.xiaozhi.xzadmin.config.Aop;

import com.alibaba.fastjson.JSONObject;
import com.xiaozhi.xzadmin.pojo.User;
import com.xiaozhi.xzadmin.pojo.system.Logininfor;
import com.xiaozhi.xzadmin.pojo.system.OperLog;
import com.xiaozhi.xzadmin.service.sys.LogininforService;
import com.xiaozhi.xzadmin.service.sys.OpenlogService;
import com.xiaozhi.xzadmin.tools.AddressUtils;
import com.xiaozhi.xzadmin.tools.CookiesUtil;
import com.xiaozhi.xzadmin.tools.IpUtils;
import eu.bitwalker.useragentutils.Browser;
import eu.bitwalker.useragentutils.OperatingSystem;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

@Aspect
@Component
@Slf4j
public class AopLoggerAspect {
    @Autowired
    private LogininforService logininforService;
    @Autowired
    private OpenlogService openlogService;

    @Pointcut("@annotation(com.xiaozhi.xzadmin.config.Aop.AopLogger)")
    public void aopLoggerAspect() {
    }

    /**
     * 环绕触发
     *
     * @param point
     * @return
     */
    @Around("aopLoggerAspect()")
    public Object doAround(ProceedingJoinPoint point) {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
        HttpServletRequest request = servletRequestAttributes.getRequest();
        Object result = null;
        long startTime = System.currentTimeMillis();
        try {
            result = point.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            log.error(throwable.getMessage());
        }
        String title = getAopLoggerDescribe(point);
        if (StringUtils.isBlank(title)) {
            title = "-";
        }
        String agent=request.getHeader("User-Agent");
        //解析agent字符串
        UserAgent userAgent = UserAgent.parseUserAgentString(agent);
        //获取浏览器对象
        Browser browser = userAgent.getBrowser();
        //获取操作系统对象
        OperatingSystem operatingSystem = userAgent.getOperatingSystem();

        if ("登录验证".equals(title) || "登录退出".equals(title)){
            Logininfor logininfor = new Logininfor();
            if ("登录退出".equals(title)){
                logininfor.setLoginName(CookiesUtil.getCookieByName(request, "username").getValue());
            }else {
                User user = (User) getFieldsName(point).get("user");
                logininfor.setLoginName(user.getUsername());
            }
            String ipAddr = IpUtils.getIpAddr(request);
            //出参获取
            JSONObject json=(JSONObject) JSONObject.toJSON(result);

            logininfor.setIpaddr(ipAddr);
            logininfor.setLoginLocation(AddressUtils.getRealAddressByIP(ipAddr));
            logininfor.setBrowser(browser.getName());
            logininfor.setOs(operatingSystem.getName());
            logininfor.setStatus("0");
            if ("500".equals(json.get("code")) || "退出成功".equals(json.get("msg"))){
                logininfor.setStatus("1");
            }
            logininfor.setMsg((String) json.get("msg"));
            logininforService.insetlogininfor(logininfor);

        }else {
            int type = getAopLoggerType(point);
            OperLog operLog = new OperLog();
            //请求标题
            operLog.setTitle(title);
            //请求类型
            operLog.setBusinessType(type);
            //请求方法
            operLog.setMethod(point.getSignature().getDeclaringTypeName()+"."+point.getSignature().getName());
//            请求方式
            operLog.setRequestMethod(request.getMethod());
//            操作人员
            operLog.setOperName(CookiesUtil.getCookieByName(request, "username").getValue());
//            请求地址
            operLog.setOperUrl(String.valueOf(request.getRequestURL()));
//            主机地址
            operLog.setOperIp(IpUtils.getIpAddr(request));
//            操作地点
            operLog.setOperLocation(AddressUtils.getRealAddressByIP(IpUtils.getIpAddr(request)));
//          请求参数
            operLog.setOperParam(String.valueOf(getFieldsName(point)));
//            返回参数
            operLog.setJsonResult(String.valueOf(result));
//            操作状态
            operLog.setStatus(0);
            if (result!=null){
                try {
                    //出参获取
                    JSONObject json=(JSONObject) JSONObject.toJSON(result);
                    if ("500".equals(json.get("code"))){
                        operLog.setStatus(1);
                    }
                }catch (ClassCastException e){

                }
            }
            openlogService.insetopenlog(operLog);


        }

        return result;
    }

    /**
     * 获取注解中对方法的描述title信息
     *
     * @param joinPoint 切点
     * @return title
     */
    public static String getAopLoggerDescribe(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        AopLogger controllerLog = method.getAnnotation(AopLogger.class);
        return controllerLog.title();
    }
    /**
     * 获取注解中对方法的描述type信息
     *
     * @param joinPoint 切点
     * @return type
     */
    public static int getAopLoggerType(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        AopLogger controllerLog = method.getAnnotation(AopLogger.class);
        return controllerLog.type();
    }

    /**
     * 获取参数列表
     *
     * @param joinPoint
     * @return
     * @throws ClassNotFoundException
     * @throws NoSuchMethodException
     */
    private static Map<String, Object> getFieldsName(ProceedingJoinPoint joinPoint) {
        // 参数值
        Object[] args = joinPoint.getArgs();
        ParameterNameDiscoverer pnd = new DefaultParameterNameDiscoverer();
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        String[] parameterNames = pnd.getParameterNames(method);
        Map<String, Object> paramMap = new HashMap<>();
        for (int i = 0; i < parameterNames.length; i++) {
            paramMap.put(parameterNames[i], args[i]);
        }
        paramMap.remove("request");
        paramMap.remove("response");
        return paramMap;
    }
}
